// ## 一个简单的事件发射器类，使用订阅发布者模式解耦，用于管理事件的注册和触发。
class EventEmitter {
    // 使用 WeakMap 存储私有数据，替代私有字段 # 兼容低版本浏览器，以确保每个实例都有自己的数据
    static listeners = new WeakMap();

    // 创建一个 Symbol 作为私有方法的标识符，替代私有方法 # 兼容低版本浏览器。
    static validateSymbol = Symbol('validateEventName');

    // 构造函数，用于初始化实例
    constructor() {
        // 初始化私有数据，用于存储事件名称及其对应的回调函数集合。
        EventEmitter.listeners.set(this, new Map());

        // 定义私有方法
        this[EventEmitter.validateSymbol] = (eventName) => {
            if (typeof eventName !== 'string' || !eventName.match(/^[A-Z0-9:_]+$/)) {
                throw new Error('无效的事件名称');
            }
        };
    }

    /**
     * ## 为指定事件添加一个回调函数，可以添加多个回调函数。
     * @param {string} eventName - 要监听的事件名称。
     * @param {Function} callback - 当事件被触发时执行的回调函数。
     * @throws {Error} 如果回调不是函数，则抛出错误。
     */
    $on(eventName, callback) {
        // 验证事件名称合法性
        this[EventEmitter.validateSymbol](eventName);
        if (typeof callback !== 'function') {
            throw new Error('回调必须是函数');
        }
        // 获取私有数据
        const listeners = EventEmitter.listeners.get(this);
        // 检查当前事件是否已经有监听器，如果没有则创建一个新的Set集合
        if (!listeners.has(eventName)) {
            listeners.set(eventName, new Set());
        }
        // 将新的回调函数添加到该事件的监听器集合中
        listeners.get(eventName).add(callback);
    }

    /**
     * ## 触发指定事件，导致所有注册的回调函数被调用。
     * @param {string} eventName - 要触发的事件名称。
     * @param {...any} args - 传递给回调函数的参数。
     */
    $emit(eventName, ...args) {
        // 验证事件名称合法性
        this[EventEmitter.validateSymbol](eventName);
        // 获取私有数据
        const listeners = EventEmitter.listeners.get(this);
        // 检查是否存在指定事件的回调函数列表
        if (listeners.has(eventName)) {
            // 遍历事件的每个回调函数，并使用提供的参数调用它们
            listeners.get(eventName).forEach(callback => {
                try {
                    callback(...args);
                } catch (error) {
                    console.error(`事件 "${eventName}" 的回调中发生错误:`, error);
                }
            });
        }
    }

    /**
     * 从指定事件中移除一个回调函数，如果没有指定回调函数，则移除所有回调函数。
     * @param {string} eventName - 要移除回调的事件名称。
     * @param {Function} callback - 要移除的回调函数。
     * @throws {Error} 如果回调不是函数，则抛出错误。
     */
    $off(eventName, callback) {
        // 验证事件名称合法性
        this[EventEmitter.validateSymbol](eventName);
        if (typeof callback !== 'function') {
            throw new Error('回调必须是函数');
        }
        // 获取私有数据
        const listeners = EventEmitter.listeners.get(this);
        // 检查是否存在指定事件的回调函数列表
        if (listeners.has(eventName)) {
            const callbacks = listeners.get(eventName);
            callbacks.delete(callback);
            if (callbacks.size === 0) {
                listeners.delete(eventName);
            }
        }
    }
}

// 导出事件发射器实例
export const emitter = new EventEmitter()